﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
using MALRECrewrite.Models;
using System.Threading.Tasks;
using System.Linq;

namespace MALRECrewrite.Etc
{
    internal class DataSaver
    {
        private string FILEPATH;

        public DataSaver()
        {
            FILEPATH = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"MALRECRewrite\{0}.xml");
        }

        public List<Anime> Animes { get; set; }
        public List<GenreCache> GenreCache { get; set; }
        public List<SortedRecommendation> Blacklist { get; set; }


        public void SaveData(ViewModels.ViewModel vm)
        {
            Serialize<List<Anime>>(String.Format(FILEPATH,"animes"), vm.Animes);
            Serialize<List<SortedRecommendation>>(String.Format(FILEPATH, "blacklist"), vm.Blacklist.ToList());

            List<GenreCache> g = new List<Etc.GenreCache>();
            foreach (KeyValuePair<int, List<string>> kvp in vm.GenreCache)
            {
                g.Add(new GenreCache(kvp));
            }

            Serialize<List<GenreCache>>(String.Format(FILEPATH, "genres"), g);
        }

        public async Task<bool> LoadData(ViewModels.ViewModel vm)
        {
            vm.IsLoadingFromSave = true;

            List<Anime> l = null;
            List<SortedRecommendation> r = new List<SortedRecommendation>();
            List<GenreCache> g = new List<GenreCache>();
            await TaskEx.Run(() =>
                {
                    try
                    {
                        l = Deserialize<List<Anime>>(String.Format(FILEPATH, "animes"));
                    }
                    catch (Exception)
                    {
                        l = null;
                    }

                    try
                    {
                        r = Deserialize<List<SortedRecommendation>>(String.Format(FILEPATH, "blacklist"));
                    }
                    catch (Exception)
                    {
                        r = null;
                    }

                    try
                    {
                        g = Deserialize<List<GenreCache>>(String.Format(FILEPATH, "genres"));
                    }
                    catch (Exception)
                    {
                        g = null;
                    }
                });

            if (l == null)
                return false;

            vm.Animes = l;
            if(r != null)
                vm.Blacklist = new System.Collections.ObjectModel.ObservableCollection<SortedRecommendation>(r);
            
            foreach (GenreCache gc in g)
            {
                vm.GenreCache.Add(gc.Key, gc.Values);
            }

            vm.IsLoadingFromSave = false;
            return true;
        }

        public void SaveSequels(ViewModels.SequelsViewModel sm)
        {
            foreach (SeasonAnime s in sm.SequelRefs)
            {
                s.ReferenceAids = new List<int>(s.References.Select(x => x.Aid));
                s.ParentAids= new List<int>(s.Parents.Select(x => x.Aid));
            }

            Serialize<List<SeasonAnime>>(String.Format(FILEPATH, "sequels"), sm.SequelRefs);
        }

        public async Task<bool> LoadSequelsData(ViewModels.SequelsViewModel sm)
        {

            List<SeasonAnime> sa = null;
            await TaskEx.Run(() =>
            {
                try
                {
                    sa = Deserialize<List<SeasonAnime>>(String.Format(FILEPATH, "sequels"));
                }
                catch (Exception)
                {
                    sa = null;
                }
            });

            if (sa == null)
                return false;

            sm.SequelRefs = sa;
            sa.ForEach(x => x.CreateReferencesFromAids());

            return true;
        }

        private void Serialize<T>(string filename, T data)
        {
            TextWriter writer = null;
            try
            {
                if(!Directory.Exists(Path.GetDirectoryName(filename)))
                    Directory.CreateDirectory(Path.GetDirectoryName(filename));
                
                writer = new StreamWriter(filename);
                XmlSerializer serializer = new XmlSerializer(typeof(T));
                serializer.Serialize(writer, data);
            }
            finally
            {
                if (writer != null)
                {
                    writer.Close();
                }
            }
        }

        private T Deserialize<T>(string filename)
        {
            TextReader reader = null;
            T data = default(T);
            try
            {
                reader = new StreamReader(filename);
                XmlSerializer serializer = new XmlSerializer(typeof(T));
                data = (T)serializer.Deserialize(reader);
            }
            finally
            {
                if (reader != null)
                {
                    reader.Close();
                }

                if (data == null)
                    throw new Exception();
            }

            return data;
        }
    }

    public class GenreCache
    {
        public int Key { get; set; }
        public List<string> Values { get; set; }

        public GenreCache()
        {
        }

        public GenreCache(KeyValuePair<int,List<string>> kvp)
        {
            Key = kvp.Key;
            Values = kvp.Value;
        }
    }
}